package com.audaque.springboot.foshanupload.web.esdatademo.service.impl;


import cn.hutool.json.JSONUtil;
import com.audaque.springboot.foshanupload.web.esdatademo.constant.MemberType;
import com.audaque.springboot.foshanupload.web.esdatademo.model.pojo.NestedFamily;
import com.audaque.springboot.foshanupload.web.esdatademo.service.NestedFamilyService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class NestedFamilyServiceImpl implements NestedFamilyService {

    private static final Log log = LogFactory.getLog(JoinFamilyServiceImpl.class);

    @Autowired
    RestHighLevelClient client;

    @Override
    public void addGrandPa(String name) {
        String id = UUID.randomUUID().toString();
        log.debug(id);
        NestedFamily grand = new NestedFamily();
        grand.setName(name);
        grand.setLevel(MemberType.GrandParent.getLevel());
        grand.setMy_id(id);
        this.addFamilyMember(grand);

    }

    private void addFamilyMember(NestedFamily familyMember) {
        IndexRequest indexRequest = new IndexRequest("my-nested-family").source(JSONUtil.toJsonStr(familyMember), XContentType.JSON)
                .id(familyMember.getMy_id()).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        try {
            IndexResponse out= client.index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("",e);
        }

    }

    @Override
    public void addParent(String grandPaId, String name) throws IOException {
        NestedFamily grand=this.getFamilyTree(grandPaId);
        log.debug(grand);
        String id = UUID.randomUUID().toString();
        log.debug(id);
        NestedFamily pa = new NestedFamily();
        pa.setName(name);
        pa.setLevel(MemberType.Parent.getLevel());
        pa.setMy_id(id);
        List<NestedFamily> children = grand.getChild()==null? new LinkedList<>():grand.getChild();
        children.add(pa);
        grand.setChild(children);
        this.addFamilyMember(grand);
    }

    @Override
    public void addChild(String parentId, String name) throws IOException {
        String indexName="my-nested-family";
        SearchRequest search= new SearchRequest(indexName);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        NestedQueryBuilder nested=QueryBuilders.nestedQuery("child",QueryBuilders.matchQuery("child.my_id", parentId),ScoreMode.None);
        searchSourceBuilder.query(nested);
        search.source(searchSourceBuilder);
        SearchResponse response=client.search(search, RequestOptions.DEFAULT);

        SearchHits hits=response.getHits();
        long total=hits.getTotalHits().value;
        if(total !=1){
            throw new RuntimeException("should be one!!");
        }
        SearchHit hit=hits.getHits()[0];
        NestedFamily grand=JSONUtil.toBean(hit.getSourceAsString(),NestedFamily.class);
        log.debug(grand);
        NestedFamily parent=grand.getChild().stream().filter( me -> me.getMy_id().equals(parentId))
                .collect(Collectors.toList()).get(0);
        String id = UUID.randomUUID().toString();
        log.debug(id);
        NestedFamily child = new NestedFamily();
        child.setName(name);
        child.setLevel(MemberType.Child.getLevel());
        child.setMy_id(id);
        List<NestedFamily> children = parent.getChild()==null? new LinkedList<>():parent.getChild();
        children.add(child);
        parent.setChild(children);
        this.addFamilyMember(grand);

    }

    @Override
    public NestedFamily getFamilyTree(String grandPaId) throws IOException {
        String indexName="my-nested-family";
        SearchRequest search= new SearchRequest(indexName);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        MatchQueryBuilder match=QueryBuilders.matchQuery("_id", grandPaId);
        searchSourceBuilder.query(match);
        search.source(searchSourceBuilder);
        SearchResponse response=client.search(search, RequestOptions.DEFAULT);

        SearchHits hits=response.getHits();
        long total=hits.getTotalHits().value;
        if(total !=1){
            throw new RuntimeException("should be one!!");
        }
        SearchHit hit=hits.getHits()[0];
        NestedFamily grand=JSONUtil.toBean(hit.getSourceAsString(),NestedFamily.class);
        return grand;
    }

    @Override
    public NestedFamily findFamilyMemberById(String id) throws IOException {
        return null;
    }
}
